function FaceRecognitionApp
    % 人脸识别系统主界面
    % 基于PCA算法的人脸识别应用
    
    % 创建主窗口
    mainFig = figure('Name', '基于PCA的人脸识别系统', 'NumberTitle', 'off', ...
                     'Position', [200, 200, 1000, 600], 'Resize', 'off', ...
                     'MenuBar', 'none', 'ToolBar', 'none', 'Color', [0.94 0.94 0.94]);
    
    % 全局变量
    appData = struct();
    appData.trainFolder = '';
    appData.testImage = '';
    appData.trainFaces = [];
    appData.trainLabels = [];
    appData.meanFace = [];
    appData.eigenFaces = [];
    appData.weightedTrain = [];
    appData.projectMatrix = [];
    appData.trained = false;
    appData.svmModel = [];  % 新增：存储SVM模型
    appData.classificationMethod = 'euclidean';  % 新增：分类方法，默认为欧式距离
    
    % === 左侧面板: 参数配置 ===
    leftPanel = uipanel('Parent', mainFig, 'Title', '参数配置', ...
                'Position', [0.02, 0.02, 0.3, 0.96], ...
                'FontSize', 12, 'FontWeight', 'bold');
    
    % 主成分贡献率控制
    uicontrol('Parent', leftPanel, 'Style', 'text', ...
              'String', '主成分贡献率 (0-1):', ...
              'Position', [20, 520, 150, 20], ...
              'HorizontalAlignment', 'left', 'FontSize', 10);
    appData.pcaRatioSlider = uicontrol('Parent', leftPanel, 'Style', 'slider', ...
                             'Min', 0.5, 'Max', 1, 'Value', 0.95, ...
                             'Position', [20, 490, 200, 20], ...
                             'Callback', @updatePcaRatioText);
    appData.pcaRatioText = uicontrol('Parent', leftPanel, 'Style', 'text', ...
                           'String', '0.95', ...
                           'Position', [230, 490, 50, 20], ...
                           'HorizontalAlignment', 'left', 'FontSize', 10);
    
    % 训练图像数量控制
    uicontrol('Parent', leftPanel, 'Style', 'text', ...
              'String', '每人训练图像数量 (1-10):', ...
              'Position', [20, 450, 160, 20], ...
              'HorizontalAlignment', 'left', 'FontSize', 10);
    appData.trainCountSlider = uicontrol('Parent', leftPanel, 'Style', 'slider', ...
                              'Min', 1, 'Max', 10, 'Value', 5, ...
                              'Position', [20, 420, 200, 20], ...
                              'SliderStep', [0.1 0.1], ...
                              'Callback', @updateTrainCountText);
    appData.trainCountText = uicontrol('Parent', leftPanel, 'Style', 'text', ...
                            'String', '5', ...
                            'Position', [230, 420, 50, 20], ...
                            'HorizontalAlignment', 'left', 'FontSize', 10);
    
    % 分类方法选择 - 使用简单按钮方式
    uicontrol('Parent', leftPanel, 'Style', 'text', ...
              'String', '【分类方法选择】:', ...
              'Position', [20, 385, 150, 20], ...
              'HorizontalAlignment', 'left', 'FontSize', 11, ...
              'FontWeight', 'bold', 'ForegroundColor', [0 0.4 0.8]);
    
    % 欧式距离分类按钮
    appData.euclideanButton = uicontrol('Parent', leftPanel, 'Style', 'togglebutton', ...
                             'String', '✓ 欧式距离分类', ...
                             'Position', [20, 350, 115, 30], ...
                             'FontSize', 10, ...
                             'FontWeight', 'bold', ...
                             'BackgroundColor', [0.7 0.9 0.7], ...
                             'ForegroundColor', [0 0.5 0], ...
                             'Value', 1, ...
                             'Callback', @selectEuclideanMethod);
    
    % SVM分类按钮
    appData.svmButton = uicontrol('Parent', leftPanel, 'Style', 'togglebutton', ...
                        'String', 'SVM分类', ...
                        'Position', [145, 350, 115, 30], ...
                        'FontSize', 10, ...
                        'FontWeight', 'bold', ...
                        'BackgroundColor', [0.9 0.9 0.9], ...
                        'ForegroundColor', [0.5 0.5 0.5], ...
                        'Value', 0, ...
                        'Callback', @selectSVMMethod);
    
    % 训练集选择按钮
    uicontrol('Parent', leftPanel, 'Style', 'pushbutton', ...
              'String', '选择训练集文件夹', ...
              'Position', [20, 310, 250, 35], ...
              'FontSize', 10, 'FontWeight', 'bold', ...
              'BackgroundColor', [0.3 0.6 0.9], ...
              'ForegroundColor', [1 1 1], ...
              'Callback', @selectTrainFolder);
    
    % 训练按钮
    appData.trainButton = uicontrol('Parent', leftPanel, 'Style', 'pushbutton', ...
                        'String', '开始训练', ...
                        'Position', [20, 265, 250, 35], ...
                        'FontSize', 10, 'FontWeight', 'bold', ...
                        'BackgroundColor', [0.2 0.7 0.3], ...
                        'ForegroundColor', [1 1 1], ...
                        'Callback', @trainModel);
    
    % 查看特征脸按钮
    appData.eigenFaceButton = uicontrol('Parent', leftPanel, 'Style', 'pushbutton', ...
                             'String', '查看特征脸', ...
                             'Position', [20, 220, 250, 35], ...
                             'FontSize', 10, 'FontWeight', 'bold', ...
                             'BackgroundColor', [0.8 0.4 0.2], ...
                             'ForegroundColor', [1 1 1], ...
                             'Enable', 'off', ...
                             'Callback', @showEigenFaces);
    
    % 测试图像选择按钮
    appData.testButton = uicontrol('Parent', leftPanel, 'Style', 'pushbutton', ...
                       'String', '选择待识别人脸', ...
                       'Position', [20, 175, 250, 35], ...
                       'FontSize', 10, 'FontWeight', 'bold', ...
                       'BackgroundColor', [0.5 0.5 0.8], ...
                       'ForegroundColor', [1 1 1], ...
                       'Enable', 'off', ...
                       'Callback', @selectTestImage);
    
    % 开始识别按钮
    appData.recognizeButton = uicontrol('Parent', leftPanel, 'Style', 'pushbutton', ...
                            'String', '开始识别', ...
                            'Position', [20, 130, 120, 35], ...
                            'FontSize', 10, 'FontWeight', 'bold', ...
                            'BackgroundColor', [0.8 0.3 0.3], ...
                            'ForegroundColor', [1 1 1], ...
                            'Enable', 'off', ...
                            'Callback', @recognizeFace);
    
    % 识别所有按钮
    appData.recognizeAllButton = uicontrol('Parent', leftPanel, 'Style', 'pushbutton', ...
                            'String', '识别所有', ...
                            'Position', [150, 130, 120, 35], ...
                            'FontSize', 10, 'FontWeight', 'bold', ...
                            'BackgroundColor', [0.6 0.2 0.7], ...
                            'ForegroundColor', [1 1 1], ...
                            'Enable', 'off', ...
                            'Callback', @recognizeAll);
    
    % 状态显示
    uicontrol('Parent', leftPanel, 'Style', 'text', ...
              'String', '当前状态:', ...
              'Position', [20, 75, 60, 20], ...
              'HorizontalAlignment', 'left', 'FontSize', 10);
    appData.statusText = uicontrol('Parent', leftPanel, 'Style', 'text', ...
                        'String', '等待选择训练集...', ...
                        'Position', [20, 45, 250, 30], ...
                        'HorizontalAlignment', 'left', 'FontSize', 9, ...
                        'ForegroundColor', [0.7 0 0]);
    
    % 分类方法显示
    uicontrol('Parent', leftPanel, 'Style', 'text', ...
              'String', '当前方法:', ...
              'Position', [20, 25, 60, 20], ...
              'HorizontalAlignment', 'left', 'FontSize', 10);
    appData.methodText = uicontrol('Parent', leftPanel, 'Style', 'text', ...
                        'String', '欧式距离分类', ...
                        'Position', [90, 25, 180, 20], ...
                        'HorizontalAlignment', 'left', 'FontSize', 10, ...
                        'ForegroundColor', [0 0.5 0]);
    
    % === 中间面板: 显示区域 ===
    centerPanel = uipanel('Parent', mainFig, 'Title', '显示区域', ...
                  'Position', [0.34, 0.02, 0.64, 0.96], ...
                  'FontSize', 12, 'FontWeight', 'bold');
    
    % 训练集信息
    appData.trainInfoPanel = uipanel('Parent', centerPanel, 'Title', '训练集信息', ...
                           'Position', [0.02, 0.7, 0.96, 0.28], ...
                           'FontSize', 10, 'FontWeight', 'bold');
    appData.trainInfoText = uicontrol('Parent', appData.trainInfoPanel, 'Style', 'text', ...
                           'String', '未选择训练集', ...
                           'Position', [10, 10, 580, 110], ...
                           'HorizontalAlignment', 'left', 'FontSize', 10);
    
    % 原始图像和识别结果
    appData.testPanel = uipanel('Parent', centerPanel, 'Title', '测试图像', ...
                     'Position', [0.02, 0.02, 0.45, 0.65], ...
                     'FontSize', 10, 'FontWeight', 'bold');
    appData.testAxes = axes('Parent', appData.testPanel, 'Position', [0.1, 0.1, 0.8, 0.8]);
    axis(appData.testAxes, 'off');
    
    appData.resultPanel = uipanel('Parent', centerPanel, 'Title', '识别结果', ...
                       'Position', [0.53, 0.02, 0.45, 0.65], ...
                       'FontSize', 10, 'FontWeight', 'bold');
    appData.resultAxes = axes('Parent', appData.resultPanel, 'Position', [0.1, 0.3, 0.8, 0.6]);
    axis(appData.resultAxes, 'off');
    appData.resultText = uicontrol('Parent', appData.resultPanel, 'Style', 'text', ...
                         'String', '', ...
                         'Position', [20, 20, 250, 40], ...
                         'HorizontalAlignment', 'left', 'FontSize', 10, ...
                         'ForegroundColor', [0 0 0.7]);
    
    % UI控件回调函数
    function updatePcaRatioText(src, ~)
        val = get(src, 'Value');
        set(appData.pcaRatioText, 'String', num2str(val, '%.2f'));
    end

    function updateTrainCountText(src, ~)
        val = round(get(src, 'Value'));
        set(src, 'Value', val);
        set(appData.trainCountText, 'String', num2str(val));
    end

    function selectEuclideanMethod(~, ~)
        appData.classificationMethod = 'euclidean';
        set(appData.methodText, 'String', '欧式距离分类');
        
        % 更新按钮状态
        set(appData.euclideanButton, 'Value', 1, 'String', '✓ 欧式距离分类', ...
            'BackgroundColor', [0.7 0.9 0.7], 'ForegroundColor', [0 0.5 0]);
        set(appData.svmButton, 'Value', 0, 'String', 'SVM分类', ...
            'BackgroundColor', [0.9 0.9 0.9], 'ForegroundColor', [0.5 0.5 0.5]);
    end

    function selectSVMMethod(~, ~)
        appData.classificationMethod = 'svm';
        set(appData.methodText, 'String', 'SVM分类');
        
        % 更新按钮状态
        set(appData.svmButton, 'Value', 1, 'String', '✓ SVM分类', ...
            'BackgroundColor', [0.7 0.9 0.7], 'ForegroundColor', [0 0.5 0]);
        set(appData.euclideanButton, 'Value', 0, 'String', '欧式距离分类', ...
            'BackgroundColor', [0.9 0.9 0.9], 'ForegroundColor', [0.5 0.5 0.5]);
    end

    function selectTrainFolder(~, ~)
        fprintf('\n===== 选择训练集文件夹 =====\n');
        initialPath = 'D:\文档资料\OneDrive\桌面\人脸配准(眉毛特征点)\train';
        fprintf('默认训练集路径: %s\n', initialPath);
        
        folderPath = uigetdir(initialPath, '选择训练集文件夹');
        
        % 使用isequal而不是==来比较
        if isequal(folderPath, 0)
            fprintf('用户取消了选择训练集操作\n');
            fprintf('===== 训练集选择已取消 =====\n\n');
            return; % 用户取消了，直接返回
        end
        
        % 到这里说明用户选择了文件夹
        appData.trainFolder = folderPath;
        fprintf('已选择训练集文件夹: %s\n', appData.trainFolder);
        
        % 检查文件夹是否存在
        if ~exist(appData.trainFolder, 'dir')
            fprintf('警告: 选择的文件夹不存在\n');
            msgbox('选择的文件夹不存在!', '警告', 'warn');
            appData.trainFolder = ''; % 重置为空
            return;
        end
        
        set(appData.statusText, 'String', '训练集已选择，等待训练...');
        set(appData.trainInfoText, 'String', ['已选择训练集: ', appData.trainFolder]);
        fprintf('准备开始训练，请点击"开始训练"按钮\n');
        fprintf('===== 训练集选择完成 =====\n\n');
    end

    function trainModel(~, ~)
        disp('DEBUG: 训练按钮被点击!'); % 简单调试输出，确认函数被调用
        
        % 修复条件判断，正确处理不同类型的比较
        if isempty(appData.trainFolder) || isequal(appData.trainFolder, 0) || strcmp(appData.trainFolder, '')
            disp('DEBUG: 训练文件夹未选择或无效');
            msgbox('请先选择训练集文件夹!', '错误', 'error');
            return;
        end
        
        % 确保文件夹存在
        if ~exist(appData.trainFolder, 'dir')
            disp(['DEBUG: 训练文件夹不存在: ', appData.trainFolder]);
            msgbox('选择的训练集文件夹不存在!', '错误', 'error');
            return;
        end
        
        % 获取参数
        pcaRatio = get(appData.pcaRatioSlider, 'Value');
        trainCount = round(get(appData.trainCountSlider, 'Value'));
        
        disp(['DEBUG: 训练参数 - pcaRatio=', num2str(pcaRatio), ', trainCount=', num2str(trainCount)]);
        disp(['DEBUG: 训练文件夹路径 = ', appData.trainFolder]);
        
        % 更新状态
        set(appData.statusText, 'String', '正在训练中...');
        drawnow;
        
        % 输出训练开始信息
        fprintf('\n===== 开始训练模型 =====\n');
        fprintf('训练集文件夹: %s\n', appData.trainFolder);
        fprintf('每人训练图像数: %d\n', trainCount);
        fprintf('主成分贡献率: %.2f\n', pcaRatio);
        
        % 记录训练开始时间
        trainStartTime = tic;
        
        % 调用PCA训练函数
        try
            fprintf('调用trainPCA函数开始训练...\n');
            disp('DEBUG: 准备调用trainPCA函数');
            [appData.trainFaces, appData.trainLabels, appData.meanFace, ...
             appData.eigenFaces, appData.weightedTrain, appData.projectMatrix, personCount] = ...
                trainPCA(appData.trainFolder, trainCount, pcaRatio);
            
            % 计算训练耗时
            trainTime = toc(trainStartTime);
            fprintf('训练完成! 总耗时: %.2f秒\n', trainTime);
            
            % 输出训练结果详情
            fprintf('\n训练结果统计:\n');
            fprintf('- 总人数: %d\n', personCount);
            fprintf('- 每人训练图像: %d\n', trainCount);
            fprintf('- 总训练图像: %d\n', personCount*trainCount);
            fprintf('- 特征脸数量: %d\n', size(appData.eigenFaces, 2));
            fprintf('- 原始维度: %d\n', size(appData.trainFaces, 1));
            fprintf('- 降维后维度: %d\n', size(appData.eigenFaces, 2));
            fprintf('- 维度压缩率: %.2f%%\n', (1 - size(appData.eigenFaces, 2)/size(appData.trainFaces, 1))*100);
            
            % 如果选择SVM分类，则训练SVM模型
            if strcmp(appData.classificationMethod, 'svm')
                fprintf('\n开始训练SVM模型...\n');
                svmTrainTime = tic;
                
                % 使用PCA降维后的特征训练SVM
                % 对于35人每人8张图片的数据规模，使用RBF核
                fprintf('使用RBF核函数训练SVM模型...\n');
                
                % 准备SVM训练数据
                X_train = appData.weightedTrain';  % 转置，每行是一个样本
                Y_train = appData.trainLabels;
                
                % 训练多分类SVM模型
                % 对于这个数据规模，使用'rbf'核函数，自动参数调优
                appData.svmModel = fitcecoc(X_train, Y_train, ...
                    'Learners', templateSVM('KernelFunction', 'rbf', ...
                                           'KernelScale', 'auto', ...
                                           'BoxConstraint', 1), ...
                    'Verbose', 1);
                
                svmTime = toc(svmTrainTime);
                fprintf('SVM模型训练完成! 耗时: %.2f秒\n', svmTime);
                fprintf('SVM模型信息: %d分类器，RBF核函数\n', length(appData.svmModel.BinaryLearners));
                trainTime = trainTime + svmTime;
            else
                appData.svmModel = [];  % 清空SVM模型
            end
            
            % 更新训练信息
            if strcmp(appData.classificationMethod, 'svm')
                infoStr = sprintf(['训练完成!\n', ...
                                  '共包含 %d 个人，每人训练 %d 张图像\n', ...
                                  '共使用 %d 张训练图像\n', ...
                                  '特征脸数量: %d\n', ...
                                  '主成分贡献率: %.2f\n', ...
                                  '分类方法: SVM (RBF核)\n', ...
                                  '训练耗时: %.2f秒'], ...
                                  personCount, trainCount, personCount*trainCount, ...
                                  size(appData.eigenFaces, 2), pcaRatio, trainTime);
            else
                infoStr = sprintf(['训练完成!\n', ...
                                  '共包含 %d 个人，每人训练 %d 张图像\n', ...
                                  '共使用 %d 张训练图像\n', ...
                                  '特征脸数量: %d\n', ...
                                  '主成分贡献率: %.2f\n', ...
                                  '分类方法: 欧式距离\n', ...
                                  '训练耗时: %.2f秒'], ...
                                  personCount, trainCount, personCount*trainCount, ...
                                  size(appData.eigenFaces, 2), pcaRatio, trainTime);
            end
            set(appData.trainInfoText, 'String', infoStr);
            set(appData.statusText, 'String', '训练完成，可以识别');
            
            % 启用相关按钮
            set(appData.eigenFaceButton, 'Enable', 'on');
            set(appData.testButton, 'Enable', 'on');
            set(appData.recognizeAllButton, 'Enable', 'on');
            appData.trained = true;
            
            fprintf('===== 训练模型完成 =====\n\n');
        catch ME
            disp(['DEBUG: 训练过程出错: ', ME.message]);
            fprintf('训练失败: %s\n', ME.message);
            fprintf('错误位置: %s\n', ME.stack(1).name);
            msgbox(['训练失败: ', ME.message], '错误', 'error');
            set(appData.statusText, 'String', '训练失败');
        end
    end

    function showEigenFaces(~, ~)
        if ~appData.trained || isempty(appData.eigenFaces)
            msgbox('请先完成训练!', '错误', 'error');
            return;
        end
        
        fprintf('\n===== 显示特征脸 =====\n');
        
        % 获取特征脸总数
        totalEigenFaces = size(appData.eigenFaces, 2);
        fprintf('特征脸总数: %d\n', totalEigenFaces);
        
        % 弹出对话框让用户选择要显示的特征脸数量
        maxDisplay = min(25, totalEigenFaces); % 最多显示25个，避免界面太拥挤
        prompt = sprintf('请输入要显示的特征脸数量\n(可显示范围: 1-%d)\n最多显示25个，避免界面太拥挤', maxDisplay);
        dlgtitle = '选择特征脸数量';
        defaultans = {num2str(min(16, maxDisplay))};
        options.Resize = 'on';
        answer = inputdlg(prompt, dlgtitle, [1 50], defaultans, options);
        
        % 检查用户是否取消了对话框
        if isempty(answer)
            fprintf('用户取消了特征脸显示操作\n');
            fprintf('===== 特征脸显示已取消 =====\n\n');
            return;
        end
        
        % 验证用户输入
        numEigenFacesToShow = str2double(answer{1});
        if isnan(numEigenFacesToShow) || numEigenFacesToShow < 1 || numEigenFacesToShow > maxDisplay
            msgbox(sprintf('请输入1到%d之间的整数!', maxDisplay), '输入错误', 'error');
            fprintf('输入无效: %s\n', answer{1});
            return;
        end
        
        % 确保不超过实际的特征脸数量
        numEigenFacesToShow = min(numEigenFacesToShow, totalEigenFaces);
        numEigenFacesToShow = round(numEigenFacesToShow); % 确保是整数
        
        fprintf('用户选择显示%d个特征脸\n', numEigenFacesToShow);
        
        % 创建新窗口显示特征脸
        eigenFig = figure('Name', sprintf('特征脸 (显示前%d个)', numEigenFacesToShow), 'NumberTitle', 'off', ...
                         'Position', [300, 200, 1000, 700]);
        
        % 计算显示布局（包含平均脸）
        totalImages = numEigenFacesToShow + 1; % +1 for mean face
        rows = floor(sqrt(totalImages));
        cols = ceil(totalImages / rows);
        
        % 如果特征脸数量较多，适当调整布局
        if numEigenFacesToShow > 16
            cols = min(6, cols); % 限制最大列数为6
            rows = ceil(totalImages / cols);
        end
        
        fprintf('显示布局: %d行 x %d列\n', rows, cols);
        
        % 显示平均脸
        subplot(rows, cols, 1);
        imgSize = sqrt(size(appData.meanFace, 1));
        imshow(reshape(appData.meanFace, imgSize, imgSize), []);
        title('平均脸', 'FontSize', 10, 'FontWeight', 'bold');
        fprintf('显示平均脸（%d x %d像素）\n', imgSize, imgSize);
        
        % 显示特征脸
        fprintf('开始显示特征脸...\n');
        for i = 1:numEigenFacesToShow
            subplot(rows, cols, i+1);
            eigenFace = reshape(appData.eigenFaces(:,i), imgSize, imgSize);
            imshow(eigenFace, []);
            title(sprintf('特征脸 #%d', i), 'FontSize', 9);
            
            % 每显示5个特征脸输出一次进度
            if mod(i, 5) == 0 || i == numEigenFacesToShow
                fprintf('    已显示%d/%d个特征脸\n', i, numEigenFacesToShow);
            end
        end
        
        % 调整子图间距
        set(eigenFig, 'Units', 'normalized');
        h = get(eigenFig, 'Children');
        if length(h) > 1
            % 设置更紧凑的布局
            for j = 1:length(h)
                if strcmp(get(h(j), 'Type'), 'axes')
                    set(h(j), 'Units', 'normalized');
                    pos = get(h(j), 'Position');
                    % 稍微缩小子图，增加间距
                    set(h(j), 'Position', [pos(1), pos(2), pos(3)*0.9, pos(4)*0.9]);
                end
            end
        end
        
        fprintf('特征脸显示完成，共显示%d个特征脸\n', numEigenFacesToShow);
        fprintf('===== 特征脸显示结束 =====\n\n');
    end

    function selectTestImage(~, ~)
        if ~appData.trained
            msgbox('请先完成训练!', '错误', 'error');
            return;
        end
        
        fprintf('\n===== 选择测试图像 =====\n');
        initialPath = 'D:\文档资料\OneDrive\桌面\人脸配准眉毛特征点\test';
        fprintf('默认测试图像路径: %s\n', initialPath);
        
        [filename, pathname] = uigetfile({'*.jpg;*.png;*.bmp', 'Image Files (*.jpg, *.png, *.bmp)'}, ...
                                         '选择测试图像', initialPath);
        
        % 使用isequal而不是==来比较
        if isequal(filename, 0) || isequal(pathname, 0)
            fprintf('用户取消了选择测试图像操作\n');
            fprintf('===== 测试图像选择已取消 =====\n\n');
            return;
        end
        
        appData.testImage = fullfile(pathname, filename);
        fprintf('已选择测试图像: %s\n', appData.testImage);
        
        % 检查文件是否存在
        if ~exist(appData.testImage, 'file')
            fprintf('警告: 选择的图像文件不存在\n');
            msgbox('选择的图像文件不存在!', '警告', 'warn');
            appData.testImage = '';
            return;
        end
        
        % 显示测试图像
        try
            testImg = imread(appData.testImage);
            if size(testImg, 3) == 3
                fprintf('将彩色图像转换为灰度图像\n');
                testImg = rgb2gray(testImg);
            end
            imshow(testImg, 'Parent', appData.testAxes);
            title(appData.testAxes, '待识别图像');
            fprintf('测试图像已显示在界面上\n');
            
            % 启用识别按钮
            set(appData.recognizeButton, 'Enable', 'on');
            set(appData.statusText, 'String', '测试图像已加载，可以开始识别');
            fprintf('准备开始识别，请点击"开始识别"按钮\n');
            fprintf('===== 测试图像选择完成 =====\n\n');
        catch ME
            fprintf('错误: 无法读取或显示图像 - %s\n', ME.message);
            msgbox(['读取图像失败: ', ME.message], '错误', 'error');
            appData.testImage = '';
        end
    end

    function recognizeFace(~, ~)
        if isempty(appData.testImage) || ~appData.trained
            msgbox('请先选择测试图像并完成训练!', '错误', 'error');
            return;
        end
        
        % 更新状态
        set(appData.statusText, 'String', '正在识别中...');
        drawnow;
        
        try
            fprintf('===== 开始人脸识别 =====\n');
            
            % 读取并预处理测试图像
            fprintf('【步骤1/5】读取测试图像: %s\n', appData.testImage);
            testImg = imread(appData.testImage);
            if size(testImg, 3) == 3
                fprintf('    将彩色图像转换为灰度图像\n');
                testImg = rgb2gray(testImg);
            end
            
            % 调整大小与训练集一致
            imgSize = sqrt(size(appData.meanFace, 1));
            if size(testImg, 1) ~= imgSize || size(testImg, 2) ~= imgSize
                fprintf('    调整图像尺寸为 %d x %d\n', imgSize, imgSize);
                testImg = imresize(testImg, [imgSize imgSize]);
            end
            
            % 将图像转换为向量
            fprintf('【步骤2/5】将图像转换为向量\n');
            testVector = double(testImg(:));
            
            % 投影到特征空间
            fprintf('【步骤3/5】将图像投影到特征空间（%d维）\n', size(appData.projectMatrix, 2));
            testWeight = appData.projectMatrix' * (testVector - appData.meanFace);
            
            % 根据选择的分类方法进行识别
            fprintf('【步骤4/5】使用%s进行分类\n', appData.classificationMethod);
            
            if strcmp(appData.classificationMethod, 'svm')
                % 使用SVM分类
                if isempty(appData.svmModel)
                    error('SVM模型未训练，请先完成SVM训练');
                end
                
                fprintf('    使用SVM模型进行预测...\n');
                
                % 准备测试数据
                X_test = testWeight';  % 转置为行向量
                
                % 使用SVM预测
                [recognizedLabel, scores] = predict(appData.svmModel, X_test);
                
                % 计算可信度（基于决策函数的输出）
                maxScore = max(scores);
                secondMaxScore = max(scores(scores < maxScore));
                if isempty(secondMaxScore)
                    secondMaxScore = 0;
                end
                confidence = max(0, min(100, (maxScore - secondMaxScore) / (maxScore + 1e-6) * 100));
                
                fprintf('    SVM预测结果: 人物 #%d，可信度: %.2f%%\n', recognizedLabel, confidence);
                
            else
                % 使用欧式距离分类
                numTrainSamples = size(appData.weightedTrain, 2);
                distances = zeros(1, numTrainSamples);
                
                fprintf('    计算与%d个训练样本的欧氏距离\n', numTrainSamples);
                for i = 1:numTrainSamples
                    distances(i) = norm(testWeight - appData.weightedTrain(:,i));
                end
                
                [minDist, minIdx] = min(distances);
                recognizedLabel = appData.trainLabels(minIdx);
                
                % 计算可信度 (简单方法: 基于距离的归一化)
                maxDist = max(distances);
                confidence = (1 - minDist/maxDist) * 100;
                
                fprintf('    欧式距离识别结果: 人物 #%d，最小距离: %.4f，可信度: %.2f%%\n', recognizedLabel, minDist, confidence);
            end
            
            fprintf('【步骤5/5】识别结果分析\n');
            fprintf('    分类方法: %s\n', appData.classificationMethod);
            fprintf('    识别结果: 人物 #%d\n', recognizedLabel);
            fprintf('    可信度: %.2f%%\n', confidence);
            
            % 找到训练集中该人的图像
            matchIndices = find(appData.trainLabels == recognizedLabel);
            if ~isempty(matchIndices)
                % 改为直接从训练集文件夹读取匹配的原始图像，而不是使用预处理后的数据
                sampleIdx = matchIndices(1);
                fprintf('    查找匹配人物的原始图像...\n');
                
                % 获取训练集中该人的所有图像文件
                imgExtensions = {'.jpg', '.png', '.bmp', '.jpeg', '.tif'};
                allFiles = [];
                
                for i = 1:length(imgExtensions)
                    pattern = ['*' imgExtensions{i}];
                    files = dir(fullfile(appData.trainFolder, pattern));
                    allFiles = [allFiles; files];
                end
                
                % 查找匹配人物ID的图像
                matchingFiles = {};
                for i = 1:length(allFiles)
                    filename = allFiles(i).name;
                    tokens = regexp(filename, '(\d+)[-_](\d+)', 'tokens');
                    if ~isempty(tokens)
                        filePersonID = str2double(tokens{1}{1});
                        if filePersonID == recognizedLabel
                            matchingFiles{end+1} = fullfile(appData.trainFolder, filename);
                        end
                    end
                end
                
                if ~isempty(matchingFiles)
                    % 读取第一张匹配的图像
                    fprintf('    找到匹配人物的原始图像: %s\n', matchingFiles{1});
                    matchedFaceImg = imread(matchingFiles{1});
                    if size(matchedFaceImg, 3) == 3
                        matchedFaceImg = rgb2gray(matchedFaceImg);
                    end
                    
                    % 显示匹配的人脸
                    imshow(matchedFaceImg, 'Parent', appData.resultAxes);
                    title(appData.resultAxes, ['识别结果: 人物#', num2str(recognizedLabel)]);
                else
                    % 如果找不到原始图像，则使用预处理后的数据（作为备选）
                    fprintf('    未找到匹配人物的原始图像，使用训练数据显示\n');
                    matchedFace = appData.trainFaces(:, sampleIdx);
                    matchedFaceImg = reshape(matchedFace, imgSize, imgSize);
                    % 归一化显示
                    matchedFaceImg = (matchedFaceImg - min(matchedFaceImg(:))) / (max(matchedFaceImg(:)) - min(matchedFaceImg(:)));
                    imshow(matchedFaceImg, 'Parent', appData.resultAxes);
                    title(appData.resultAxes, ['识别结果: 人物#', num2str(recognizedLabel)]);
                end
                
                % 显示识别结果信息
                methodStr = '';
                if strcmp(appData.classificationMethod, 'svm')
                    methodStr = 'SVM分类';
                else
                    methodStr = '欧式距离';
                end
                resultStr = sprintf(['识别结果: 人物 #%d\n', ...
                                    '分类方法: %s\n', ...
                                    '可信度: %.2f%%'], ...
                                    recognizedLabel, methodStr, confidence);
                set(appData.resultText, 'String', resultStr);
                
                fprintf('    在UI中显示匹配的训练图像\n');
            end
            
            set(appData.statusText, 'String', '识别完成');
            fprintf('===== 人脸识别完成 =====\n\n');
            
        catch ME
            disp(['DEBUG: 识别过程出错: ', ME.message]);
            fprintf('识别失败: %s\n', ME.message);
            fprintf('错误位置: %s\n', ME.stack(1).name);
            msgbox(['识别失败: ', ME.message], '错误', 'error');
            set(appData.statusText, 'String', '识别失败');
        end
    end

    function recognizeAll(~, ~)
        if ~appData.trained
            msgbox('请先完成训练!', '错误', 'error');
            return;
        end
        
        % 更新状态
        set(appData.statusText, 'String', '正在识别所有人...');
        drawnow;
        
        try
            fprintf('===== 开始识别所有人（每人最后一张图） =====\n');
            
            % 获取训练集中所有图像文件
            imgExtensions = {'.jpg', '.png', '.bmp', '.jpeg', '.tif'};
            allFiles = [];
            
            for i = 1:length(imgExtensions)
                pattern = ['*' imgExtensions{i}];
                files = dir(fullfile(appData.trainFolder, pattern));
                allFiles = [allFiles; files];
            end
            
            if isempty(allFiles)
                msgbox('训练集文件夹中未找到图像文件!', '错误', 'error');
                return;
            end
            
            % 解析文件名获取人物ID和图像序号
            fprintf('【步骤1/4】解析训练集文件，查找每人最后一张图...\n');
            personImages = containers.Map('KeyType', 'int32', 'ValueType', 'any');
            
            for i = 1:length(allFiles)
                filename = allFiles(i).name;
                tokens = regexp(filename, '(\d+)[-_](\d+)', 'tokens');
                if ~isempty(tokens)
                    personID = str2double(tokens{1}{1});
                    imageSeq = str2double(tokens{1}{2});
                    
                    if isKey(personImages, personID)
                        currentImages = personImages(personID);
                        currentImages(end+1, :) = [imageSeq, i]; % [序号, 文件索引]
                        personImages(personID) = currentImages;
                    else
                        personImages(personID) = [imageSeq, i];
                    end
                end
            end
            
            % 为每个人选择最后一张图（序号最大的图）
            fprintf('【步骤2/4】为每个人选择最后一张图像...\n');
            personIDs = keys(personImages);
            testImages = [];
            testPersonIDs = [];
            
            for i = 1:length(personIDs)
                personID = personIDs{i};
                images = personImages(personID);
                [~, maxIdx] = max(images(:, 1)); % 找到序号最大的图像
                fileIdx = images(maxIdx, 2);
                testImages = [testImages; allFiles(fileIdx)];
                testPersonIDs = [testPersonIDs; personID];
                fprintf('    人物ID %d: 选择图像 %s\n', personID, allFiles(fileIdx).name);
            end
            
            % 开始批量识别
            fprintf('【步骤3/4】开始批量识别 %d 张图像...\n', length(testImages));
            
            correctCount = 0;
            totalCount = length(testImages);
            results = {};
            recognizedImages = {};  % 存储识别出的对应图像
            allTestImages = testImages;  % 保存所有测试图像信息
            allTestPersonIDs = testPersonIDs;
            
            % 执行批量识别（不显示界面）
            for i = 1:totalCount
                % 读取测试图像
                testImagePath = fullfile(appData.trainFolder, testImages(i).name);
                actualPersonID = testPersonIDs(i);
                
                fprintf('  正在识别第 %d/%d 张: %s (实际人物ID: %d)\n', ...
                       i, totalCount, testImages(i).name, actualPersonID);
                
                % 执行识别
                try
                    % 读取并预处理测试图像
                    testImg = imread(testImagePath);
                    if size(testImg, 3) == 3
                        testImg = rgb2gray(testImg);
                    end
                    
                    % 调整大小与训练集一致
                    imgSize = sqrt(size(appData.meanFace, 1));
                    if size(testImg, 1) ~= imgSize || size(testImg, 2) ~= imgSize
                        testImg = imresize(testImg, [imgSize imgSize]);
                    end
                    
                    % 将图像转换为向量并投影到特征空间
                    testVector = double(testImg(:));
                    testWeight = appData.projectMatrix' * (testVector - appData.meanFace);
                    
                    % 根据分类方法进行识别
                    if strcmp(appData.classificationMethod, 'svm')
                        % 使用SVM分类
                        X_test = testWeight';
                        [recognizedLabel, scores] = predict(appData.svmModel, X_test);
                        
                        % 计算可信度
                        maxScore = max(scores);
                        secondMaxScore = max(scores(scores < maxScore));
                        if isempty(secondMaxScore)
                            secondMaxScore = 0;
                        end
                        confidence = max(0, min(100, (maxScore - secondMaxScore) / (maxScore + 1e-6) * 100));
                    else
                        % 使用欧式距离分类
                        numTrainSamples = size(appData.weightedTrain, 2);
                        distances = zeros(1, numTrainSamples);
                        
                        for j = 1:numTrainSamples
                            distances(j) = norm(testWeight - appData.weightedTrain(:,j));
                        end
                        
                        [minDist, minIdx] = min(distances);
                        recognizedLabel = appData.trainLabels(minIdx);
                        
                        % 计算可信度
                        maxDist = max(distances);
                        confidence = (1 - minDist/maxDist) * 100;
                    end
                    
                    % 查找识别结果对应的训练图像
                    matchedTrainImage = '';
                    % 修复：查找该人在训练集中的任意一张图像
                    % 首先收集该人物ID的所有图像
                    candidateImages = {};
                    for j = 1:length(allFiles)
                        filename = allFiles(j).name;
                        tokens = regexp(filename, '(\d+)[-_](\d+)', 'tokens');
                        if ~isempty(tokens)
                            filePersonID = str2double(tokens{1}{1});
                            if filePersonID == recognizedLabel
                                candidateImages{end+1} = fullfile(appData.trainFolder, allFiles(j).name);
                            end
                        end
                    end
                    
                    % 如果找到该人的图像，选择第一张作为展示
                    if ~isempty(candidateImages)
                        matchedTrainImage = candidateImages{1};
                    end
                    
                    % 判断识别是否正确
                    isCorrect = (recognizedLabel == actualPersonID);
                    if isCorrect
                        correctCount = correctCount + 1;
                        resultStr = '✓ 正确';
                        fprintf('    识别结果: %d -> %d ✓ 正确 (可信度: %.2f%%)\n', ...
                               actualPersonID, recognizedLabel, confidence);
                    else
                        resultStr = '✗ 错误';
                        fprintf('    识别结果: %d -> %d ✗ 错误 (可信度: %.2f%%)\n', ...
                               actualPersonID, recognizedLabel, confidence);
                    end
                    
                    % 保存结果
                    results{i} = struct('testImage', testImagePath, ...
                                       'actualID', actualPersonID, ...
                                       'recognizedID', recognizedLabel, ...
                                       'confidence', confidence, ...
                                       'isCorrect', isCorrect, ...
                                       'resultStr', resultStr, ...
                                       'matchedImage', matchedTrainImage, ...
                                       'filename', testImages(i).name);
                    
                catch ME
                    fprintf('    识别失败: %s\n', ME.message);
                    results{i} = struct('testImage', testImagePath, ...
                                       'actualID', actualPersonID, ...
                                       'recognizedID', -1, ...
                                       'confidence', 0, ...
                                       'isCorrect', false, ...
                                       'resultStr', '识别失败', ...
                                       'matchedImage', '', ...
                                       'filename', testImages(i).name);
                end
                
                % 更新进度
                accuracy = correctCount / i * 100;
                set(appData.statusText, 'String', sprintf('识别进度: %d/%d (准确率: %.1f%%)', ...
                                                         i, totalCount, accuracy));
            end
            
            % 显示最终结果
            fprintf('【步骤4/4】显示识别结果界面...\n');
            finalAccuracy = correctCount / totalCount * 100;
            
            % 创建新的识别结果查看窗口
            createRecognitionResultViewer(results, finalAccuracy, correctCount, totalCount);
            
            % 更新主界面状态
            set(appData.statusText, 'String', sprintf('批量识别完成 (准确率: %.1f%%)', finalAccuracy));
            
            % 在命令窗口输出详细结果
            fprintf('\n===== 批量识别完成 =====\n');
            fprintf('识别总结:\n');
            fprintf('- 总图像数: %d\n', totalCount);
            fprintf('- 识别正确: %d\n', correctCount);
            fprintf('- 识别错误: %d\n', totalCount - correctCount);
            fprintf('- 识别准确率: %.2f%%\n', finalAccuracy);
            fprintf('- 分类方法: %s\n', appData.classificationMethod);
            fprintf('\n详细结果:\n');
            for i = 1:length(results)
                fprintf('  %s: 实际ID=%d, 识别ID=%d, %s, 可信度=%.1f%%\n', ...
                       results{i}.filename, results{i}.actualID, results{i}.recognizedID, ...
                       results{i}.resultStr, results{i}.confidence);
            end
            fprintf('===== 批量识别报告结束 =====\n\n');
            
        catch ME
            fprintf('批量识别失败: %s\n', ME.message);
            fprintf('错误位置: %s\n', ME.stack(1).name);
            msgbox(['批量识别失败: ', ME.message], '错误', 'error');
            set(appData.statusText, 'String', '批量识别失败');
        end
    end

    % 创建识别结果查看器
    function createRecognitionResultViewer(results, accuracy, correctCount, totalCount)
        % 创建结果查看窗口
        resultFig = figure('Name', '批量识别结果查看器', 'NumberTitle', 'off', ...
                          'Position', [100, 100, 1200, 700], 'Resize', 'off', ...
                          'CloseRequestFcn', @(src,evt) delete(src));
        
        % 创建全局变量存储结果数据
        resultData = struct();
        resultData.results = results;
        resultData.currentIndex = 1;
        resultData.totalCount = length(results);
        
        % 顶部统计信息面板
        statsPanel = uipanel('Parent', resultFig, 'Title', '识别统计', ...
                             'Position', [0.02, 0.85, 0.96, 0.13], ...
                             'FontSize', 12, 'FontWeight', 'bold', ...
                             'BackgroundColor', [0.95 0.95 0.95]);
        
        % 统计信息文本
        statsStr = sprintf(['批量识别完成！  总数：%d    正确：%d    错误：%d    准确率：%.2f%%    方法：%s'], ...
                          totalCount, correctCount, totalCount - correctCount, accuracy, appData.classificationMethod);
        uicontrol('Parent', statsPanel, 'Style', 'text', ...
                 'String', statsStr, ...
                 'Position', [20, 25, 1120, 30], ...
                 'HorizontalAlignment', 'center', 'FontSize', 14, ...
                 'FontWeight', 'bold', 'ForegroundColor', [0 0.4 0.8], ...
                 'BackgroundColor', [0.95 0.95 0.95]);
        
        % 导航控制面板
        navPanel = uipanel('Parent', resultFig, 'Title', '导航控制', ...
                          'Position', [0.02, 0.75, 0.96, 0.08], ...
                          'FontSize', 11, 'FontWeight', 'bold');
        
        % 上一个按钮
        resultData.prevButton = uicontrol('Parent', navPanel, 'Style', 'pushbutton', ...
                                'String', '◀ 上一个', ...
                                'Position', [50, 15, 80, 30], ...
                                'FontSize', 10, 'FontWeight', 'bold', ...
                                'BackgroundColor', [0.3 0.6 0.9], ...
                                'ForegroundColor', [1 1 1], ...
                                'Callback', @(src,evt) navigateResult(-1));
        
        % 下一个按钮
        resultData.nextButton = uicontrol('Parent', navPanel, 'Style', 'pushbutton', ...
                               'String', '下一个 ▶', ...
                               'Position', [140, 15, 80, 30], ...
                               'FontSize', 10, 'FontWeight', 'bold', ...
                               'BackgroundColor', [0.3 0.6 0.9], ...
                               'ForegroundColor', [1 1 1], ...
                               'Callback', @(src,evt) navigateResult(1));
        
        % 当前位置显示
        resultData.positionText = uicontrol('Parent', navPanel, 'Style', 'text', ...
                                  'String', sprintf('第 %d / %d 个', 1, totalCount), ...
                                  'Position', [250, 20, 100, 20], ...
                                  'HorizontalAlignment', 'center', 'FontSize', 11, ...
                                  'FontWeight', 'bold');
        
        % 跳转到指定序号
        uicontrol('Parent', navPanel, 'Style', 'text', ...
                 'String', '跳转到第', ...
                 'Position', [380, 20, 60, 20], ...
                 'HorizontalAlignment', 'left', 'FontSize', 10);
        
        resultData.gotoEdit = uicontrol('Parent', navPanel, 'Style', 'edit', ...
                             'String', '1', ...
                             'Position', [445, 18, 50, 25], ...
                             'FontSize', 10, ...
                             'HorizontalAlignment', 'center');
        
        uicontrol('Parent', navPanel, 'Style', 'text', ...
                 'String', '个', ...
                 'Position', [500, 20, 20, 20], ...
                 'HorizontalAlignment', 'left', 'FontSize', 10);
        
        uicontrol('Parent', navPanel, 'Style', 'pushbutton', ...
                 'String', '跳转', ...
                 'Position', [525, 15, 50, 30], ...
                 'FontSize', 10, 'FontWeight', 'bold', ...
                 'BackgroundColor', [0.8 0.4 0.2], ...
                 'ForegroundColor', [1 1 1], ...
                 'Callback', @gotoSpecificResult);
        
        % 快速筛选按钮
        uicontrol('Parent', navPanel, 'Style', 'pushbutton', ...
                 'String', '只看错误', ...
                 'Position', [650, 15, 70, 30], ...
                 'FontSize', 10, 'FontWeight', 'bold', ...
                 'BackgroundColor', [0.8 0.3 0.3], ...
                 'ForegroundColor', [1 1 1], ...
                 'Callback', @showOnlyErrors);
        
        uicontrol('Parent', navPanel, 'Style', 'pushbutton', ...
                 'String', '显示全部', ...
                 'Position', [730, 15, 70, 30], ...
                 'FontSize', 10, 'FontWeight', 'bold', ...
                 'BackgroundColor', [0.2 0.7 0.3], ...
                 'ForegroundColor', [1 1 1], ...
                 'Callback', @showAllResults);
        
        % 图像显示区域
        imagePanel = uipanel('Parent', resultFig, 'Title', '图像对比', ...
                            'Position', [0.02, 0.25, 0.96, 0.48], ...
                            'FontSize', 12, 'FontWeight', 'bold');
        
        % 测试图像面板
        testImagePanel = uipanel('Parent', imagePanel, 'Title', '待识别图像', ...
                               'Position', [0.02, 0.02, 0.47, 0.96], ...
                               'FontSize', 11, 'FontWeight', 'bold', ...
                               'ForegroundColor', [0 0.5 0.8]);
        resultData.testAxes = axes('Parent', testImagePanel, 'Position', [0.08, 0.15, 0.84, 0.75]);
        axis(resultData.testAxes, 'off');
        
        % 识别结果图像面板
        resultImagePanel = uipanel('Parent', imagePanel, 'Title', '识别为', ...
                                 'Position', [0.51, 0.02, 0.47, 0.96], ...
                                 'FontSize', 11, 'FontWeight', 'bold', ...
                                 'ForegroundColor', [0.8 0.5 0]);
        resultData.resultAxes = axes('Parent', resultImagePanel, 'Position', [0.08, 0.15, 0.84, 0.75]);
        axis(resultData.resultAxes, 'off');
        
        % 详细信息面板
        detailPanel = uipanel('Parent', resultFig, 'Title', '识别详情', ...
                             'Position', [0.02, 0.02, 0.96, 0.21], ...
                             'FontSize', 12, 'FontWeight', 'bold');
        
        resultData.detailText = uicontrol('Parent', detailPanel, 'Style', 'text', ...
                                'String', '', ...
                                'Position', [20, 20, 1120, 100], ...
                                'HorizontalAlignment', 'left', 'FontSize', 12, ...
                                'BackgroundColor', [0.98 0.98 0.98]);
        
        % 存储数据到窗口
        setappdata(resultFig, 'resultData', resultData);
        
        % 显示第一个结果
        displayResult(resultFig, 1);
        
        % 导航函数
        function navigateResult(direction)
            data = getappdata(resultFig, 'resultData');
            newIndex = data.currentIndex + direction;
            if newIndex >= 1 && newIndex <= data.totalCount
                displayResult(resultFig, newIndex);
            end
        end
        
        % 跳转到指定结果
        function gotoSpecificResult(~, ~)
            data = getappdata(resultFig, 'resultData');
            try
                targetIndex = str2double(get(data.gotoEdit, 'String'));
                if targetIndex >= 1 && targetIndex <= data.totalCount
                    displayResult(resultFig, targetIndex);
                else
                    msgbox(sprintf('请输入1到%d之间的数字！', data.totalCount), '输入错误', 'warn');
                    set(data.gotoEdit, 'String', num2str(data.currentIndex));
                end
            catch
                msgbox('请输入有效的数字！', '输入错误', 'error');
                set(data.gotoEdit, 'String', num2str(data.currentIndex));
            end
        end
        
        % 只显示错误结果
        function showOnlyErrors(~, ~)
            data = getappdata(resultFig, 'resultData');
            errorIndices = [];
            for i = 1:length(data.results)
                if ~data.results{i}.isCorrect
                    errorIndices(end+1) = i;
                end
            end
            
            if isempty(errorIndices)
                msgbox('没有识别错误的结果！', '信息', 'none');
                return;
            end
            
            % 创建只包含错误结果的新数据
            errorResults = {};
            for i = 1:length(errorIndices)
                errorResults{i} = data.results{errorIndices(i)};
                errorResults{i}.originalIndex = errorIndices(i);
            end
            
            data.results = errorResults;
            data.totalCount = length(errorResults);
            data.currentIndex = 1;
            data.isFiltered = true;
            data.filterType = 'errors';
            
            setappdata(resultFig, 'resultData', data);
            displayResult(resultFig, 1);
        end
        
        % 显示全部结果
        function showAllResults(~, ~)
            data = getappdata(resultFig, 'resultData');
            if isfield(data, 'isFiltered') && data.isFiltered
                % 恢复原始数据
                data.results = results;
                data.totalCount = length(results);
                data.currentIndex = 1;
                data.isFiltered = false;
                
                setappdata(resultFig, 'resultData', data);
                displayResult(resultFig, 1);
            end
        end
    end
    
    % 显示指定索引的识别结果
    function displayResult(figHandle, index)
        data = getappdata(figHandle, 'resultData');
        data.currentIndex = index;
        setappdata(figHandle, 'resultData', data);
        
        if index < 1 || index > data.totalCount
            return;
        end
        
        result = data.results{index};
        
        % 更新导航按钮状态
        set(data.prevButton, 'Enable', iif(index > 1, 'on', 'off'));
        set(data.nextButton, 'Enable', iif(index < data.totalCount, 'on', 'off'));
        
        % 更新位置显示
        if isfield(data, 'isFiltered') && data.isFiltered
            if isfield(result, 'originalIndex')
                posStr = sprintf('第 %d / %d 个 (原第 %d 个)', index, data.totalCount, result.originalIndex);
            else
                posStr = sprintf('第 %d / %d 个 (已筛选)', index, data.totalCount);
            end
        else
            posStr = sprintf('第 %d / %d 个', index, data.totalCount);
        end
        set(data.positionText, 'String', posStr);
        set(data.gotoEdit, 'String', num2str(index));
        
        % 显示测试图像
        try
            if exist(result.testImage, 'file')
                testImg = imread(result.testImage);
                if size(testImg, 3) == 3
                    testImg = rgb2gray(testImg);
                end
                imshow(testImg, 'Parent', data.testAxes);
                title(data.testAxes, sprintf('待识别：%s', result.filename), ...
                     'FontSize', 10, 'FontWeight', 'bold');
            else
                cla(data.testAxes);
                text(0.5, 0.5, '图像文件不存在', 'Parent', data.testAxes, ...
                    'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle');
                title(data.testAxes, '图像加载失败', 'FontSize', 10, 'Color', 'red');
            end
        catch
            cla(data.testAxes);
            text(0.5, 0.5, '无法加载图像', 'Parent', data.testAxes, ...
                'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle');
            title(data.testAxes, '图像加载错误', 'FontSize', 10, 'Color', 'red');
        end
        
        % 显示识别结果图像
        try
            if ~isempty(result.matchedImage) && exist(result.matchedImage, 'file')
                matchedImg = imread(result.matchedImage);
                if size(matchedImg, 3) == 3
                    matchedImg = rgb2gray(matchedImg);
                end
                imshow(matchedImg, 'Parent', data.resultAxes);
                title(data.resultAxes, sprintf('识别为：ID %d', result.recognizedID), ...
                     'FontSize', 10, 'FontWeight', 'bold');
            else
                cla(data.resultAxes);
                text(0.5, 0.5, '未找到匹配图像', 'Parent', data.resultAxes, ...
                    'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle');
                title(data.resultAxes, sprintf('识别为：ID %d', result.recognizedID), ...
                     'FontSize', 10, 'FontWeight', 'bold');
            end
        catch
            cla(data.resultAxes);
            text(0.5, 0.5, '无法显示结果', 'Parent', data.resultAxes, ...
                'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle');
            title(data.resultAxes, '结果显示错误', 'FontSize', 10, 'Color', 'red');
        end
        
        % 更新详细信息
        if result.recognizedID == -1
            detailStr = sprintf(['文件名：%s\n\n', ...
                               '实际人物ID：%d\n\n', ...
                               '识别状态：%s\n\n', ...
                               '错误信息：识别过程中发生错误'], ...
                              result.filename, result.actualID, result.resultStr);
        else
            detailStr = sprintf(['文件名：%s\n\n', ...
                               '实际人物ID：%d        识别人物ID：%d\n\n', ...
                               '识别结果：%s        可信度：%.2f%%\n\n', ...
                               '匹配图像：%s'], ...
                              result.filename, result.actualID, result.recognizedID, ...
                              result.resultStr, result.confidence, ...
                              iif(isempty(result.matchedImage), '未找到', result.matchedImage));
        end
        
        % 根据识别结果设置文本颜色
        if result.isCorrect
            textColor = [0 0.6 0]; % 绿色
        else
            textColor = [0.8 0 0]; % 红色
        end
        
        set(data.detailText, 'String', detailStr, 'ForegroundColor', textColor);
    end
    
    % 辅助函数：三元运算符
    function result = iif(condition, trueValue, falseValue)
        if condition
            result = trueValue;
        else
            result = falseValue;
        end
    end
end 